package syntelos.sx;

import alto.sec.KeyManager;
import alto.sec.TrustStore;
import alto.sec.TrustManager;

/**
 * The super class of {@link Server} is a coding layer for separating
 * the sockets configuration coding.
 * 
 * @author jdp
 * @since 1.6
 */
public abstract class ServerSocketFactory 
    extends SX.Daemon.Server
{

    static {
        syntelos.lang.Socket.SInit();
    }

    private String[] secureEnabledProtocols;

    private String[] secureEnabledCiphers;

    private javax.net.ssl.SSLContext secureContext;

    private java.security.KeyStore secureKeystore;


    public ServerSocketFactory(String name){
        super(name);
    }


    public String[] getSecureEnabledProtocols(){
        return this.secureEnabledProtocols;
    }
    public String[] getSecureEnabledCiphers(){
        return this.secureEnabledCiphers;
    }
    public javax.net.ssl.SSLContext getSecureContext(){
        return this.secureContext;
    }
    public java.security.KeyStore getSecureKeystore(){
        return this.secureKeystore;
    }
    public javax.net.ssl.KeyManager[] getSecureKeyManagers(){
        return KeyManager.Array;
    }
    public java.security.KeyStore getSecureTruststore(){
        return TrustStore.Instance;
    }
    public javax.net.ssl.TrustManager[] getSecureTrustManagers(){
        return TrustManager.Array;
    }

    public final Socket create()
        throws java.io.IOException
    {
        Server server = (Server)this;
        switch (server.getProtocolDefaultPort()){
        case Server.PORT_HTTP: {
            java.net.URL shm_url = server.getShmUrl();
            if (null != shm_url){
                syntelos.net.shm.Connection.Server shm = 
                    new syntelos.net.shm.Connection.Server(shm_url);
                return new Socket(server,shm);
            }
            else {
                java.nio.channels.ServerSocketChannel channel = 
                    java.nio.channels.ServerSocketChannel.open();
                java.net.ServerSocket socket = channel.socket();
                socket.bind(server.getInterface());
                return new Socket(server,socket);
            }
        }
        case Server.PORT_HTTPS: {
            try {
                this.secureContext = javax.net.ssl.SSLContext.getDefault();

                this.secureKeystore = this.createHTTPSKeyStore();

                this.secureContext.init(KeyManager.Array,TrustManager.Array,this.createHTTPSRNG());

                javax.net.ssl.SSLServerSocketFactory factory = this.secureContext.getServerSocketFactory();
                java.net.InetSocketAddress inf = server.getInterface();
                int port = inf.getPort();
                int backlog = 3;//(TODO)
                java.net.InetAddress dev = inf.getAddress();
                javax.net.ssl.SSLServerSocket socket;
                if (null == dev)
                    socket = (javax.net.ssl.SSLServerSocket)factory.createServerSocket(port,backlog);
                else
                    socket = (javax.net.ssl.SSLServerSocket)factory.createServerSocket(port,backlog,dev);
                socket.setWantClientAuth(true);
                socket.setEnabledProtocols(alto.lang.Socket.SSL_PROT);
                this.secureEnabledProtocols = socket.getEnabledProtocols();
                this.secureEnabledCiphers = factory.getSupportedCipherSuites();
                socket.setEnabledCipherSuites(this.secureEnabledCiphers);
                return new Socket(server,socket);
            }
            catch (java.security.NoSuchAlgorithmException exc){
                throw new alto.sys.Error.State(exc);
            }
            catch (java.security.KeyManagementException exc){
                throw new alto.sys.Error.State(exc);
            }
            catch (java.security.KeyStoreException exc){
                throw new alto.sys.Error.State(exc);
            }
            catch (java.security.cert.CertificateException exc){
                throw new alto.sys.Error.State(exc);
            }
        }
        default:
            throw new alto.sys.Error.State(server.getProtocol());
        }
    }
    private final java.security.SecureRandom createHTTPSRNG(){
        return new java.security.SecureRandom();
    }
    private final java.security.KeyStore createHTTPSKeyStore()
        throws java.io.IOException, java.security.KeyStoreException, java.security.NoSuchAlgorithmException, java.security.cert.CertificateException
    {
        Server server = (Server)this;
//        Configuration.Group config = server.getConfiguration();

        String stdKeystorePass = java.lang.System.getProperty("javax.net.ssl.keyStorePassword");
        String keystorePass = null;//config.getHTTPSKeystorePassword(stdKeystorePass);

        String stdKeystoreKeyPass = java.lang.System.getProperty("javax.net.ssl.keyStoreKeyPassword");
        String keystoreKeyPass = null;//config.getHTTPSKeystoreKeyPassword(stdKeystoreKeyPass);

        return TrustManager.Instance.reinit(keystorePass,keystoreKeyPass).getServer();
    }
}
